home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / tkern10.zip / SRC\FORMATTR.C < prev    next >
Text File  |  1994-03-01  |  14KB  |  711 lines

  1. /*
  2.  *  This file forms part of "TKERN" - "Troy's Kernel for Windows".
  3.  *
  4.  *  Copyright (C) 1994  Troy Rollo <troy@cbme.unsw.EDU.AU>
  5.  *
  6.  *  This library is free software; you can redistribute it and/or
  7.  *  modify it under the terms of the GNU Library General Public
  8.  *  License as published by the Free Software Foundation; either
  9.  *  version 2 of the License, or (at your option) any later version.
  10.  *
  11.  *  This library is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  *  Library General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU Library General Public
  17.  *  License along with this library; if not, write to the Free
  18.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /* __formattr does formatted output. It is here to serve all the printf
  22.  * type functions. They call __formatter with the address of a function
  23.  * that __formatter will call when it has a character, and a void pointer
  24.  * which is passwd to that function as the first argument. The character
  25.  * is passed as the second argument.
  26.  *
  27.  * This function can be safely placed in the DLL without sacrificing
  28.  * portability. It basically means that this module can be under GNU
  29.  * Library License without compromising any other programs using the
  30.  * stubs (which are freely redistributable and usable for any purpose
  31.  * whatsoever).
  32.  *
  33.  * Note that this also makes it trivial to design new printf type
  34.  * functions without resorting to sprintf on a large string.
  35.  */
  36.  
  37. #include <stdlib.h>
  38. #include <stdarg.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include <float.h>
  42. #include <math.h>
  43.  
  44. #define    FLAG_SHOWSIGN    0x0001
  45. #define    FLAG_LEFT    0x0002
  46. #define    FLAG_ZEROES    0x0004
  47. #define    FLAG_BLANK    0x0008
  48. #define    FLAG_ALTERNATE    0x0010
  49. #define    FLAG_UPPER    0x0020
  50. #define    FLAG_EXPONENTIAL 0x0040
  51. #define    FLAG_MAYEXP    0x0080
  52.  
  53. #pragma warn -pls
  54.  
  55. static    char    buffer[1024];
  56.  
  57.  
  58. #pragma argsused
  59. static int
  60. show_integer(    int    (*func)(void *a, char b),
  61.         void    *func_arg,
  62.         char    const *pch,
  63.         char    cSign,
  64.         int    nWidth,
  65.         int    nPrec,
  66.         int    nFlags)
  67. {
  68.     char    cFill = ((nFlags & FLAG_ZEROES) ? '0' : ' ');
  69.     int    iLen;
  70.     int    nChars = 0;
  71.  
  72.     iLen = strlen(pch) + (cSign ? 1 : 0);
  73.     if (iLen > nWidth)
  74.         nWidth = iLen;
  75.     else if (nWidth > iLen &&
  76.          (!(nFlags & FLAG_LEFT) ||
  77.          (nFlags & FLAG_ZEROES)))
  78.     {
  79.         if (cFill == '0' && cSign)
  80.         {
  81.             (*func)(func_arg, cSign);
  82.             cSign = '\0';
  83.             iLen--;
  84.             nWidth--;
  85.             nChars++;
  86.         }
  87.         while (nWidth > iLen)
  88.         {
  89.             nWidth--;
  90.             nChars++;
  91.             (*func)(func_arg, cFill);
  92.         }
  93.     }
  94.     if (cSign)
  95.     {
  96.         (*func)(func_arg, cSign);
  97.         iLen--;
  98.         nWidth--;
  99.         nChars++;
  100.     }
  101.     while (iLen--)
  102.     {
  103.         nWidth--;
  104.         (*func)(func_arg, *pch++);
  105.         nChars++;
  106.     }
  107.     while (nWidth--)
  108.     {
  109.         (*func)(func_arg, ' ');
  110.         nChars++;
  111.     }
  112.     return nChars;
  113. }
  114.  
  115.  
  116. static int    
  117. show_long(    int    (*func)(void *a, char b),
  118.         void    *func_arg,
  119.         long    number,
  120.         int    nWidth,
  121.         int    nPrec,
  122.         int    nFlags)
  123. {
  124.     char    *pch = buffer;
  125.     char    cSign = '\0';
  126.     int    nLen;
  127.  
  128.     ltoa(number, buffer, 10);
  129.     if (*pch == '-')
  130.     {
  131.         cSign = '-';
  132.         pch++;
  133.     }
  134.     else if (nFlags & FLAG_SHOWSIGN)
  135.     {
  136.         cSign = '+';
  137.     }
  138.     else if (nFlags & FLAG_BLANK)
  139.     {
  140.         cSign = ' ';
  141.     }
  142.     return show_integer(func, func_arg, pch, cSign, nWidth, nPrec, nFlags);
  143. }
  144.         
  145. static int    
  146. show_ulong(    int    (*func)(void *a, char b),
  147.         void    *func_arg,
  148.         long    number,
  149.         int    nWidth,
  150.         int    nPrec,
  151.         int    nFlags)
  152. {
  153.     ultoa(number, buffer, 10);
  154.     return show_integer(func, func_arg, buffer, '\0', nWidth, nPrec, nFlags);
  155. }
  156.         
  157. static int    
  158. show_hex(    int    (*func)(void *a, char b),
  159.         void    *func_arg,
  160.         long    number,
  161.         int    nWidth,
  162.         int    nPrec,
  163.         int    nFlags)
  164. {
  165.     ultoa(number, buffer, 16);
  166.     if (nFlags & FLAG_UPPER)
  167.         strupr(buffer);
  168.     return show_integer(func, func_arg, buffer, '\0', nWidth, nPrec, nFlags);
  169. }
  170.  
  171. static    int
  172. show_real(    int    (*func)(void *a, char b),
  173.         void    *func_arg,
  174.         long double fValue,
  175.         int    nWidth,
  176.         int    nPrecision,
  177.         int    nFlags,
  178.         int    nDigits)
  179. {
  180.     int    aiDigits[LDBL_DIG + 1];
  181.     long    double    fMantissa;
  182.     int    nExponent;
  183.     int    nSign = 1;
  184.     int    nVisible;
  185.     char    achExponent[10];
  186.     int    nWritten = 0;
  187.     int    iLastDigit;
  188.     int    *piStart;
  189.     char    *pchStart;
  190.     int    i;
  191.  
  192.     if (fValue < 0)
  193.     {
  194.         nSign = -1;
  195.         fValue = -fValue;
  196.     }
  197.     if (fValue)
  198.         nExponent = floor(log10(fValue));
  199.     else
  200.         nExponent = 0;
  201.     fMantissa = fValue / pow(10, nExponent);
  202.  
  203.     aiDigits[0] = 0;
  204.     for (i = 1; i <= nDigits; i++)
  205.     {
  206.         if (fMantissa < 0) /* Rounding error */
  207.             fMantissa = 0;
  208.         aiDigits[i] = floor(fMantissa);
  209.         fMantissa = (fMantissa - aiDigits[i]) * 10;
  210.     }
  211.     for (; i < nDigits; i++)
  212.     {
  213.         aiDigits[i] = 0;
  214.     }
  215.     if (nPrecision == -1)
  216.         nPrecision = 6;
  217.     if (nFlags & FLAG_MAYEXP &&
  218.         nExponent >= 0 &&
  219.         nExponent +
  220.          (nPrecision ? nPrecision + 2 : 1) +
  221.          ((nSign == -1 || (nFlags & FLAG_SHOWSIGN)) ? 1 : 0) > nWidth)
  222.         nFlags |= FLAG_EXPONENTIAL;
  223.     if (nFlags & FLAG_EXPONENTIAL)
  224.     {
  225.         ltoa(nExponent, achExponent, 10);
  226.         nVisible = 1 + (nPrecision ? nPrecision + 2 : 1) + strlen(achExponent);
  227.     }
  228.     else
  229.     {
  230.         if (nExponent < 0)
  231.         {
  232.             nVisible = nPrecision ? nPrecision : 1;
  233.         }
  234.         else
  235.         {
  236.             nVisible = nExponent + (nPrecision ? nPrecision + 2 : 1);
  237.         }
  238.     }
  239.     if (nSign == -1 || nFlags & FLAG_SHOWSIGN)
  240.         nVisible++;
  241.     if (!(nFlags & FLAG_LEFT))
  242.     {
  243.         while (nVisible < nWidth--)
  244.         {
  245.             (*func)(func_arg, ' ');
  246.             nWritten++;
  247.         }
  248.     }
  249.  
  250.     if ((nFlags & FLAG_EXPONENTIAL) || nExponent < nDigits)
  251.     {
  252.         if ((nFlags & FLAG_EXPONENTIAL) || (nExponent < 0))
  253.         {
  254.             iLastDigit = 1 + nPrecision;
  255.         }
  256.         else
  257.         {
  258.             iLastDigit = 1 + nExponent + nPrecision;
  259.         }
  260.         if (iLastDigit < nDigits &&
  261.             aiDigits[iLastDigit+1] >= 5)
  262.         {
  263.             while (aiDigits[iLastDigit] == 9)
  264.                 aiDigits[iLastDigit--] = 0;
  265.             aiDigits[iLastDigit]++;
  266.         }
  267.     }
  268.  
  269.     if (nSign == -1)
  270.     {
  271.         (*func)(func_arg, '-');
  272.         nWritten++;
  273.     }
  274.     else if (nFlags & FLAG_SHOWSIGN)
  275.     {
  276.         (*func)(func_arg, '+');
  277.     }
  278.     if (aiDigits[0])
  279.     {
  280.         nExponent++;
  281.         piStart = aiDigits;
  282.     }
  283.     else
  284.     {
  285.         piStart = aiDigits + 1;
  286.     }
  287.     if (nFlags & FLAG_EXPONENTIAL)
  288.     {
  289.         (*func)(func_arg, '0' + *piStart++);
  290.         nWritten++;
  291.         if (nPrecision)
  292.         {
  293.             if (nPrecision > nDigits - 1)
  294.                 nPrecision = nDigits - 1;
  295.             (*func)(func_arg, '.');
  296.             nWritten++;
  297.             while(nPrecision--)
  298.             {
  299.                 (*func)(func_arg, '0' + *piStart++);
  300.                 nWritten++;
  301.             }
  302.             if (nFlags & FLAG_UPPER)
  303.                 (*func)(func_arg, 'E');
  304.             else
  305.                 (*func)(func_arg, 'e');
  306.             nWritten++;
  307.             for (pchStart = achExponent; *pchStart; pchStart++)
  308.             {
  309.                 (*func)(func_arg, *pchStart);
  310.                 nWritten++;
  311.             }
  312.         }
  313.     }
  314.     else
  315.     {
  316.         if (nExponent >= 0)
  317.         {
  318.             while (nExponent-- >= 0)
  319.             {
  320.                 if (nDigits-- > 0)
  321.                     (*func)(func_arg, '0' + *piStart++);
  322.                 else
  323.                     (*func)(func_arg, '0');
  324.                 nWritten++;
  325.             }
  326.             if (nPrecision)
  327.             {
  328.                 (*func)(func_arg, '.');
  329.                 nWritten++;
  330.             }
  331.         }
  332.         else
  333.         {
  334.             (*func)(func_arg, '0');
  335.             if (nPrecision)
  336.                 (*func)(func_arg, '.');
  337.             while (nExponent++ && nPrecision--)
  338.             {
  339.                 (*func)(func_arg, '0');
  340.                 nWritten++;
  341.             }
  342.         }
  343.         while (nPrecision-- > 0)
  344.         {
  345.             if (nDigits-- > 0)
  346.                 (*func)(func_arg, '0 ' + *piStart++);
  347.             else
  348.                 (*func)(func_arg, '0');
  349.             nWritten++;
  350.         }
  351.     }
  352.  
  353.     if (nFlags & FLAG_LEFT)
  354.     {
  355.         while (nVisible < nWidth--)
  356.         {
  357.             (*func)(func_arg, ' ');
  358.             nWritten++;
  359.         }
  360.     }
  361.  
  362.     return nWritten;
  363. }
  364.         
  365.  
  366. int far _export
  367. __formatter(    int    (*func)(void *a, char b),
  368.         void    *func_arg,
  369.         char    const *format,
  370.         va_list    arg)
  371. {
  372.     int    nChars = 0;
  373.     int    nPrecision;
  374.     int    nWidth;
  375.     int    nLong;
  376.     long    nIntValue;
  377.     int    nFlags;
  378.     int    nPad;
  379.     int    nLen;
  380.     union
  381.     {
  382.         short        nShort;
  383.         int        nInt;
  384.         long        nLong;
  385.         unsigned short    nUShort;
  386.         unsigned int    nUInt;
  387.         unsigned long    nULong;
  388.  
  389.         float        fFloat;
  390.         double        fDouble;
  391.         long double    fLongDouble;
  392.  
  393.         char        cChar;
  394.  
  395.         char        *pchString;
  396.  
  397.         void        *pvPointer;
  398.     } Value;
  399.         
  400.  
  401.     while (*format)
  402.     {
  403.         if (*format == '%')
  404.         {
  405.             if (*++format == '%')
  406.             {
  407.                 (*func)(func_arg, '%');
  408.                 nChars++;
  409.             }
  410.             else
  411.             {
  412.                 nPrecision = -1;
  413.                 nWidth = 0;
  414.                 nLong = 0;
  415.                 nFlags = 0;
  416.                 while (strchr("+-0# ", *format))
  417.                 {
  418.                     switch(*format++)
  419.                     {
  420.                     case '+':
  421.                         nFlags |= FLAG_SHOWSIGN;
  422.                         break;
  423.  
  424.                     case '-':
  425.                         nFlags |= FLAG_LEFT;
  426.                         break;
  427.  
  428.                     case '#':
  429.                         nFlags |= FLAG_ALTERNATE;
  430.                         break;
  431.  
  432.                     case '0':
  433.                         nFlags |= FLAG_ZEROES;
  434.                         break;
  435.  
  436.                     case ' ':
  437.                         nFlags |= FLAG_BLANK;
  438.                         break;
  439.                     }
  440.                 }
  441.                 if (isdigit(*format))
  442.                 {
  443.                     nWidth = (int) strtol((char *) format, (char **) &format, 10);
  444.                 }
  445.                 else if (*format == '*')
  446.                 {
  447.                     nWidth = va_arg(arg, int);
  448.                     format++;
  449.                 }
  450.                 if (*format == '.')
  451.                 {
  452.                     ++format;
  453.                     if (isdigit(*format))
  454.                     {
  455.                         nPrecision = (int) strtol((char *) format, (char **) &format, 10);
  456.                     }
  457.                     else if (*format == '*')
  458.                     {
  459.                         nPrecision = (int) va_arg(arg, int);
  460.                         format++;
  461.                     }
  462.                 }
  463.                 while (strchr("lhL", *format))
  464.                 {
  465.                     if (*format == 'l')
  466.                         nLong++;
  467.                     else if (*format == 'h')
  468.                         nLong--;
  469.                     else if (*format == 'L')
  470.                         nLong = 2;
  471.                     format++;
  472.                 }
  473.                 switch(*format)
  474.                 {
  475.                 case 'u':
  476.                 case 'U':
  477.                     if (nLong < 0)
  478.                     {
  479.                         Value.nUShort = va_arg(    arg,
  480.                                     unsigned short);
  481.                         nChars += show_ulong(    func,
  482.                                     func_arg,
  483.                                     Value.nUShort,
  484.                                     nWidth,
  485.                                     nPrecision,
  486.                                     nFlags);
  487.                     }
  488.                     else if (nLong == 0)
  489.                     {
  490.                         Value.nUInt = va_arg(    arg,
  491.                                     unsigned int);
  492.                         nChars += show_ulong(    func,
  493.                                     func_arg,
  494.                                     Value.nUInt,
  495.                                     nWidth,
  496.                                     nPrecision,
  497.                                     nFlags);
  498.                     }
  499.                     else
  500.                     {
  501.                         Value.nULong = va_arg(    arg,
  502.                                     unsigned long);
  503.                         nChars += show_ulong(    func,
  504.                                     func_arg,
  505.                                     Value.nULong,
  506.                                     nWidth,
  507.                                     nPrecision,
  508.                                     nFlags);
  509.                     }
  510.                     break;
  511.  
  512.                 case 'd':
  513.                 case 'D':
  514.                 case 'i':
  515.                 case 'I':
  516.                     if (nLong < 0)
  517.                     {
  518.                         Value.nShort = va_arg(    arg,
  519.                                     short);
  520.                         nChars += show_long(    func,
  521.                                     func_arg,
  522.                                     Value.nShort,
  523.                                     nWidth,
  524.                                     nPrecision,
  525.                                     nFlags);
  526.                     }
  527.                     else if (nLong == 0)
  528.                     {
  529.                         Value.nInt = va_arg(    arg,
  530.                                     int);
  531.                         nChars += show_long(    func,
  532.                                     func_arg,
  533.                                     Value.nInt,
  534.                                     nWidth,
  535.                                     nPrecision,
  536.                                     nFlags);
  537.                     }
  538.                     else
  539.                     {
  540.                         Value.nLong = va_arg(    arg,
  541.                                     long);
  542.                         nChars += show_ulong(    func,
  543.                                     func_arg,
  544.                                     Value.nLong,
  545.                                     nWidth,
  546.                                     nPrecision,
  547.                                     nFlags);
  548.                     }
  549.                     break;
  550.  
  551.                 case 'n':
  552.                     *(va_arg(arg, int *)) = nChars;
  553.                     break;
  554.  
  555.                 case 's':
  556.                     Value.pchString = va_arg(    arg,
  557.                                     char *);
  558.                     /* We can't do this in strlen, because we
  559.                      * can't guarantee if there is a trailing
  560.                      * 0 if we have a precision value
  561.                      */
  562.                     for (nLen = 0;
  563.                          (nPrecision < 0 ||
  564.                           nLen < nPrecision) && Value.pchString[nLen];
  565.                          nLen++);
  566.                     if (nPrecision < 0 || nLen < nPrecision)
  567.                         nPrecision = nLen;
  568.                     if (!nWidth || nPrecision > nWidth)
  569.                         nWidth = nPrecision;
  570.  
  571.                     nPad = nWidth - nPrecision;
  572.  
  573.                     if (!(nFlags & FLAG_LEFT))
  574.                     {
  575.                         while (nPad--)
  576.                         {
  577.                             (*func)(func_arg, ' ');
  578.                             nChars++;
  579.                         }
  580.                     }
  581.                     while (nPrecision--)
  582.                     {
  583.                         (*func)(func_arg, *Value.pchString++);
  584.                         nChars++;
  585.                     }
  586.                     if (nFlags & FLAG_LEFT)
  587.                     {
  588.                         while (nPad--)
  589.                         {
  590.                             (*func)(func_arg, ' ');
  591.                             nChars++;
  592.                         }
  593.                     }
  594.                     break;
  595.  
  596.                 case 'o':
  597.                 case 'O':
  598.                     break;
  599.  
  600.                 case 'x':
  601.                 case 'X':
  602.                     if (*format == 'X')
  603.                         nFlags |= FLAG_UPPER;
  604.                     if (nLong < 0)
  605.                     {
  606.                         Value.nUShort = va_arg(    arg,
  607.                                     unsigned short);
  608.                         nChars += show_hex(    func,
  609.                                     func_arg,
  610.                                     Value.nUShort,
  611.                                     nWidth,
  612.                                     nPrecision,
  613.                                     nFlags);
  614.                     }
  615.                     else if (nLong == 0)
  616.                     {
  617.                         Value.nUInt = va_arg(    arg,
  618.                                     unsigned int);
  619.                         nChars += show_hex(    func,
  620.                                     func_arg,
  621.                                     Value.nUInt,
  622.                                     nWidth,
  623.                                     nPrecision,
  624.                                     nFlags);
  625.                     }
  626.                     else
  627.                     {
  628.                         Value.nULong = va_arg(    arg,
  629.                                     unsigned long);
  630.                         nChars += show_hex(    func,
  631.                                     func_arg,
  632.                                     Value.nULong,
  633.                                     nWidth,
  634.                                     nPrecision,
  635.                                     nFlags);
  636.                     }
  637.                     break;
  638.  
  639.                 case 'c':
  640.                 case 'C':
  641.                     Value.cChar = va_arg(    arg,
  642.                                 char);
  643.                     (*func)(func_arg, Value.cChar);
  644.                     nChars++;
  645.                     break;
  646.  
  647.                 case 'P':
  648.                 case 'p':
  649.                     Value.pvPointer = va_arg(arg,
  650.                                  void *);
  651.                     break;
  652.  
  653.                 case 'E':
  654.                 case 'e':
  655.                     nFlags |= FLAG_EXPONENTIAL;
  656.                 case 'g':
  657.                 case 'G':
  658.                     nFlags |= FLAG_MAYEXP;
  659.                 case 'F':
  660.                 case 'f':
  661.                     if (nLong > 1)
  662.                     {
  663.                         Value.fLongDouble = va_arg(    arg,
  664.                                         long double);
  665.                         nChars += show_real(    func,
  666.                                     func_arg,
  667.                                     Value.fLongDouble,
  668.                                     nWidth,
  669.                                     nPrecision,
  670.                                     nFlags,
  671.                                     LDBL_DIG);
  672.                     }
  673.                     else if (nLong > 0)
  674.                     {
  675.                         Value.fDouble = va_arg(    arg,
  676.                                     double);
  677.                         nChars += show_real(    func,
  678.                                     func_arg,
  679.                                     Value.fDouble,
  680.                                     nWidth,
  681.                                     nPrecision,
  682.                                     nFlags,
  683.                                     DBL_DIG);
  684.                     }
  685.                     else
  686.                     {
  687.                         Value.fFloat = va_arg(    arg,
  688.                                     double);
  689.                         nChars += show_real(    func,
  690.                                     func_arg,
  691.                                     Value.fFloat,
  692.                                     nWidth,
  693.                                     nPrecision,
  694.                                     nFlags,
  695.                                     FLT_DIG);
  696.                     }
  697.                     break;
  698.                 }
  699.             
  700.             }
  701.         }
  702.         else
  703.         {
  704.             (*func)(func_arg, *format);
  705.             nChars++;
  706.         }
  707.         format++;
  708.     }
  709.     return nChars;
  710. }
  711.